MUI 的 Accordion 支援兩種行為:
Accordion
元件的開闔狀態各自獨立:當畫面上有複數個 Accordion
元件時,開啟 Accordion
一號不會影響畫面上其餘的 Accordion
狀態Accordion
元件時,同一時間只會有一個 AccordionBody
被展開而昨天暫時跳過的變數 hasOpenFromProps
就是為了實現第二種功能,以下是解說時段。
首先檢查是否有透過 props
傳入變數 open
:
const hasOpenFromProps = useMemo(
() => Object.keys(props).includes('open'),
[props]
);
若有,則使用 props.open
來控制 AccordionBody
開闔,反之則使用 Accordion
內部的 useState
變數 localOpen
來管理狀態:
const openToUse = useMemo(
() => (hasOpenFromProps ? open : localOpen),
[hasOpenFromProps, open, localOpen]
);
當 Accordion
透過 props.open
控制開闔時,不使用 Accordion
元件內部的 toggleAccordion
來驅動開闔狀態:
setTitleElement(
React.cloneElement(childElement, {
open: openToUse,
onClick: hasOpenFromProps ? undefined : toggleAccordion,
accordionTitleClass: classes.title,
})
);
使用方式:
function AccordionsDemo(): React.ReactElement {
const [currentOpen, setCurrentOpen] = useState<number>(0);
// 當使用者點擊各個 Accordion 元件時,設定當下需要展開的 AccordionBody
const openAccordion = (panelNumber: number) => () => {
if (panelNumber === currentOpen) {
setCurrentOpen(0);
} else {
setCurrentOpen(panelNumber);
}
};
// 每一個 Accordion 透過 props.open 比對 currentOpen 來控制當下是哪一個 AccordionBody 需要展開
return (
<Stack>
<Accordion onClick={openAccordion(1)} open={currentOpen === 1}>
<AccordionTitle>title 1</AccordionTitle>
<AccordionBody>body 1</AccordionBody>
</Accordion>
<Accordion onClick={openAccordion(2)} open={currentOpen === 2}>
<AccordionTitle>title 2</AccordionTitle>
<AccordionBody>body 2</AccordionBody>
</Accordion>
<Accordion onClick={openAccordion(3)} open={currentOpen === 3}>
<AccordionTitle>title 3</AccordionTitle>
<AccordionBody>body 3</AccordionBody>
</Accordion>
</Stack>
);
}
元件開闔的邏輯很單純,如果設計稿上 Accordion
的外觀與既有的第三方元件庫有落差的話,可以考慮自幹。
但上述的情境會帶出另一個問題:「那麼當初在選型時,是否沒有顧慮到該元件庫能與現行的設計風格搭配,才會出現元件庫不易配合設計稿的狀況」。
小結論:除了懷疑設計師為何會畫出不好實作的前端介面時,問題也有可能出在工程師挑選了不容易搭配現行設計的框架來開發。